package token

import (
	"chain_bridge_service/configs"
	"chain_bridge_service/internal/pkg/core"
	"chain_bridge_service/internal/repository/mongodb/chain_config"
	"chain_bridge_service/internal/repository/mongodb/token"
	"context"
	"errors"
	"github.com/ethereum/go-ethereum/ethclient"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
)

type CreateTokenData struct {
	Id          string `bson:"_id,omitempty" json:"id"`
	ChainName   string `bson:"chainName" json:"chainName"`
	ChainID     uint   `bson:"chainId" json:"chainId"`
	Address     string `bson:"address" json:"address"`
	Name        string `bson:"name" json:"name"`
	Symbol      string `bson:"symbol" json:"symbol"`
	Decimals    uint   `bson:"decimals" json:"decimals"`
	TotalSupply string `bson:"totalSupply" json:"totalSupply"`
	IsErc20     string `bson:"isErc20" json:"isErc20"`
	Type        string `bson:"type" json:"type"`
}

func (s *service) TokenCreate(ctx core.Context, tokenData *CreateTokenData) error {
	model := token.NewModel()
	model.Address = tokenData.Address
	data, err := model.GetInfoByAddress(s.db.GetDb())
	if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		return err
	}
	if data.Address != "" {
		return errors.New("请勿重复添加")
	}

	model.ChainName = tokenData.ChainName
	model.ChainId = tokenData.ChainID
	model.Type = tokenData.Type
	if tokenData.Type == "1" {
		model.Decimals = uint8(tokenData.Decimals)
		model.Name = tokenData.Name
		model.TotalSupply = tokenData.TotalSupply
		model.Symbol = tokenData.Symbol
	} else {
		cfg := configs.Get().Mongodb
		var scanConfig chain_config.ChainConfig
		configClient := s.db.GetDb().Database(cfg.Config.Name).Collection("scan_config")
		err = configClient.FindOne(context.TODO(), bson.M{"chainId": tokenData.ChainID, "chainName": tokenData.ChainName}).Decode(&scanConfig)
		if err != nil {
			return err
		}
		client, err := ethclient.Dial(scanConfig.RpcUrl)
		if err != nil {
			return err
		}

		err = token.ParseTokenAddress(tokenData.Address, client, model)
		if err != nil {
			return err
		}
	}

	err = model.Create(s.db.GetDb())
	return err
}

func (s *service) TokenUpdate(ctx core.Context, tokenData *CreateTokenData) error {

	model := token.NewModel()
	model.Address = tokenData.Address
	data, err := model.GetInfoByAddress(s.db.GetDb())
	if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		return err
	}
	if data.Address != "" && data.ID.Hex() != tokenData.Id {
		return errors.New("请勿重复添加")
	}

	objId, _ := primitive.ObjectIDFromHex(tokenData.Id)
	model.ID = objId
	tokenInfo, err := model.GetInfoById(s.db.GetDb())
	if err != nil {
		return err
	}

	if tokenInfo.ChainName != tokenData.ChainName || tokenInfo.Address != tokenData.Address {
		model.ChainName = tokenData.ChainName
		model.ChainId = tokenData.ChainID

		if tokenData.Type == "1" {
			cfg := configs.Get().Mongodb
			var scanConfig chain_config.ChainConfig
			configClient := s.db.GetDb().Database(cfg.Config.Name).Collection("scan_config")
			err = configClient.FindOne(context.TODO(), bson.M{"chainId": tokenData.ChainID, "chainName": tokenData.ChainName}).Decode(&scanConfig)
			if err != nil {
				return err
			}
			client, err := ethclient.Dial(scanConfig.RpcUrl)
			if err != nil {
				return err
			}
			err = token.ParseTokenAddress(tokenData.Address, client, model)
			if err != nil {
				return err
			}
			err = model.Update(s.db.GetDb())
			return err
		} else {
			model.Decimals = uint8(tokenData.Decimals)
			model.Name = tokenData.Name
			model.TotalSupply = tokenData.TotalSupply
			model.Symbol = tokenData.Symbol
		}
	}

	return nil
}

func (s *service) TokenList(ctx core.Context, pageIndex uint, pageSize uint) (productList []token.Token, err error) {
	model := token.NewModel()
	list, err := model.List(s.db.GetDb(), pageIndex, pageSize)
	return list, err
}

func (s *service) TokenCount(ctx core.Context) (int64, error) {
	model := token.NewModel()
	count, err := model.Count(s.db.GetDb())
	return count, err
}

func (s *service) Delete(ctx core.Context, tokenData *CreateTokenData) error {
	cfg := configs.Get().Mongodb
	userTokenClient := s.db.GetDb().Database(cfg.Config.Name).Collection("user_token")
	documents, err := userTokenClient.CountDocuments(context.TODO(), bson.D{{"tokenId", tokenData.Id}})
	if err != nil {
		return err
	}
	if documents != 0 {
		return errors.New("已经有客户在监听该代币,无法删除")
	}
	model := token.NewModel()
	objId, err := primitive.ObjectIDFromHex(tokenData.Id)
	model.ID = objId
	err = model.Delete(s.db.GetDb())
	return err
}
